//**************************************************************************
// Copyright 2008 Peter Project (http://www.codeplex.com/peter)
//
// License : GNU General Public License (GPL)
// For full text of the license please goto:
// http://www.gnu.org/licenses/gpl-2.0.html
//
// This code is provided on an AS IS basis, with no WARRANTIES,
// CONDITIONS or GUARANTEES of any kind.
//
//		File: PeterInterfaces.cs
//		Purpose: This file holds all the Interfaces for the Peter
//				 Plugin Architecture.
//
//**************************************************************************

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Peter
{
    /// <summary>
    /// This is the Peter application class.
    /// </summary>
    /// <remarks>
    /// Peter will detect if an instance is already running and will switch to the current running
    /// instance if it is. Otherwise it will continue to start and bring up
    /// <see cref="T:Peter.MainForm" />.
    /// </remarks>
    static class Program
    {
        static Mutex mutex;
        const int SW_RESTORE = 9;
        private const int WM_COPYDATA = 0x4A;

        [DllImport("user32.dll")]
        private static extern int ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll")]
        private static extern int SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern int IsIconic(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);


        /// <summary>
        /// GetCurrentInstanceWindowHandle
        /// </summary>
        /// <returns></returns>
        private static IntPtr GetCurrentInstanceWindowHandle()
        {
            IntPtr hWnd = IntPtr.Zero;
            Process process = Process.GetCurrentProcess();
            Process[] processes = Process.GetProcessesByName(process.ProcessName);
            foreach (Process _process in processes)
            {
                // Get the first instance that is not this instance, has the
                // same process name and was started from the same file name
                // and location. Also check that the process has a valid
                // window handle in this session to filter out other user's
                // processes.
                if (_process.Id != process.Id &&
                    _process.MainModule.FileName == process.MainModule.FileName &&
                    _process.MainWindowHandle != IntPtr.Zero)
                {
                    hWnd = _process.MainWindowHandle;
                    break;
                }
            }
            return hWnd;
        }

        /// <summary>
        /// SwitchToCurrentInstance
        /// </summary>
        private static void SwitchToCurrentInstance(List<string> args)
        {
            IntPtr hWnd = GetCurrentInstanceWindowHandle();
            if (hWnd != IntPtr.Zero)
            {
                // Send arguments...
                if (args.Count > 0)
                {
                    string data = "";
                    foreach (string arg in args)
                    {
                        data += arg + "|";
                    }
                    CopyDataStruct str = new CopyDataStruct(data);
                    IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(str));
                    Marshal.StructureToPtr(str, pnt, false);
                    SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, pnt);
                }

                // Restore window if minimised. Do not restore if already in
                // normal or maximised window state, since we don't want to
                // change the current state of the window.
                if (IsIconic(hWnd) != 0)
                {
                    ShowWindow(hWnd, SW_RESTORE);
                }

                // Set foreground window.
                SetForegroundWindow(hWnd);
            }
        }

        /// <summary>
        /// check if given exe alread running or not
        /// </summary>
        /// <returns>returns true if already running</returns>
        private static bool IsAlreadyRunning()
        {
            string strLoc = Assembly.GetExecutingAssembly().Location;
            FileSystemInfo fileInfo = new FileInfo(strLoc);
            string sExeName = fileInfo.Name;
            bool bCreatedNew;

            mutex = new Mutex(true, "Global\\" + sExeName, out bCreatedNew);
            if (bCreatedNew)
                mutex.ReleaseMutex();

            return !bCreatedNew;
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            List<string> argList = new List<string>();
            argList.AddRange(args);

            if (IsAlreadyRunning() && args.Length > 0)
            {
                SwitchToCurrentInstance(argList);
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainForm(argList));
            }
        }

        static void myReceive(string[] args)
        {
            for (int i = 0; i < args.Length; i++)
            {
                Console.WriteLine("MSG " + i.ToString() + ": " + args[i]);
            }
        }
    }

    public struct CopyDataStruct
    {
        public int dwData;
        public int cbData;
        public string lpData;

        public CopyDataStruct(string data)
        {
            this.lpData = data + "\0";
            this.cbData = data.Length;
            this.dwData = 0;
        }
    }
}
